// Package config
// Title 			nacos.config.components.go
// Description 		Nacos 配置中心工厂, 实现 factory.RemoteApplicationConfigLoaderFactory, 实现其远程加载器接口方法
// Author  			alittlexincan@163.com 					2024/07/22 11:36
// Update  			alittlexincan@163.com 					2024/07/22 11:36
package config

import "C"
import (
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/nacos-group/nacos-sdk-go/v2/clients"
	"github.com/nacos-group/nacos-sdk-go/v2/clients/config_client"
	"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
	"github.com/nacos-group/nacos-sdk-go/v2/vo"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"xincan.com.cn/tarot-go/internal/common/constants"
	"xincan.com.cn/tarot-go/internal/config/factory"
)

// nacosConfigComponent
// Title 			nacosConfigComponent
// Description 		NACOS 配置中心结构体
// Author  			alittlexincan@163.com 					2024/07/22 11:36
// Update  			alittlexincan@163.com 					2024/07/22 11:36
type nacosConfigComponent struct {
	factory.BaseConfigLoader[factory.RemoteApplicationConfigLoaderFactory]                         // 基础配置加载器, 内置全局配置和日志
	IP                                                                     string                  `mapstructure:"ip" json:"ip"`                   // 服务器IP
	Port                                                                   int                     `mapstructure:"port" json:"port"`               // 服务器端口
	Username                                                               string                  `mapstructure:"username" json:"username"`       // 用户名
	Password                                                               string                  `mapstructure:"password" json:"password"`       // 密码
	NamespaceId                                                            string                  `mapstructure:"namespaceId" json:"namespaceId"` // 命名空间ID
	Group                                                                  string                  `mapstructure:"group" json:"group"`             // 分组
	DataId                                                                 string                  `mapstructure:"dataId" json:"dataId"`           // 数据ID
	CacheDir                                                               string                  `mapstructure:"cacheDir" json:"cacheDir"`       // 缓存目录
	LogDir                                                                 string                  `mapstructure:"logDir" json:"logDir"`           // 日志目录
	localCache                                                             map[string]*viper.Viper // 本地内存缓存
	lastUpdateTime                                                         map[string]int64        // 最后更新时间
	cacheMutex                                                             sync.RWMutex            // 缓存读写锁
}

// ConfigLoad
// Title 			ConfigLoad
// Description 		实现 factory.RemoteApplicationConfigLoaderFactory 接口方法, 获取Nacos远程配置中心配置信息
// Author  			alittlexincan@163.com 					2024/07/22 11:36
// Update  			alittlexincan@163.com 					2024/07/22 11:36
// Return    		*viper.Viper     						返回配置实例
func (nacos *nacosConfigComponent) ConfigLoad() (*viper.Viper, factory.RemoteApplicationConfigLoaderFactory) {

	if nacos.localCache == nil {
		nacos.localCache = make(map[string]*viper.Viper)
	}
	if nacos.lastUpdateTime == nil {
		nacos.lastUpdateTime = make(map[string]int64)
	}

	cacheKey := nacos.DataId + ":" + nacos.Group

	// 先检查本地缓存（带读锁）
	nacos.cacheMutex.RLock()
	if cache, exists := nacos.localCache[cacheKey]; exists {
		if time.Now().Unix()-nacos.lastUpdateTime[cacheKey] < 30 { // 30秒缓存
			nacos.cacheMutex.RUnlock()
			nacos.Logger.Debug("从本地缓存加载配置")
			return cache, nacos
		}
	}
	nacos.cacheMutex.RUnlock()

	// 1. 创建Nacos配置客户端
	configClient := nacos.setNacosConfigServer()
	// 2. 获取Nacos配置内容
	content, err := configClient.GetConfig(vo.ConfigParam{DataId: nacos.DataId, Group: nacos.Group})
	if err != nil {
		nacos.Logger.Error("获取配置内容失败", zap.Error(err))
	}
	// 3. 创建新的Viper实例
	nacosViper := viper.New()
	nacosViper.SetConfigType(constants.DefaultConfigSuffix)
	// 4. 从字符串读取配置
	if err := nacosViper.ReadConfig(strings.NewReader(content)); err != nil {
		nacos.Logger.Error("加载远程配置信息失败", zap.Error(err))
		return nil, nil
	}

	// 更新缓存（写锁）
	nacos.cacheMutex.Lock()
	nacos.localCache[cacheKey] = nacosViper
	nacos.lastUpdateTime[cacheKey] = time.Now().Unix()
	nacos.cacheMutex.Unlock()

	nacos.Logger.Info("加载远程配置信息成功", zap.Any("remote", nacosViper.AllSettings()))
	return nacosViper, nacos
}

// WatchRemoteConfigLoad
// Title 			WatchRemoteConfigLoad
// Description 		实现 factory.RemoteApplicationConfigLoaderFactory 接口方法, 获取系统整体配置, (根据当前需求进行设置)
// Author      		alittlexincan@163.com 								2024/07/22 11:36
// Update  			alittlexincan@163.com 								2024/07/22 11:36
// Param    		callback factory.WatchRemoteConfigLoadParam 		返回监听结果
func (nacos *nacosConfigComponent) WatchRemoteConfigLoad(callback factory.ConfigWatchRemoteConfigLoadFunc) {
	// 1. 创建Nacos配置客户端
	configClient := nacos.setNacosConfigServer()

	// 使用带缓冲的通道处理配置变更，避免阻塞
	changeChan := make(chan vo.ConfigParam, 10)

	go func() {
		for configParam := range changeChan {
			// 异步处理配置变更，避免阻塞监听线程
			go nacos.handleConfigChange(configParam, callback)
		}
	}()

	if err := configClient.ListenConfig(
		vo.ConfigParam{DataId: nacos.DataId, Group: nacos.Group, OnChange: func(namespace, group, dataId, data string) {
			watchViper := viper.New()
			watchViper.SetConfigType(constants.DefaultConfigSuffix)
			if err := watchViper.ReadConfig(strings.NewReader(data)); err != nil {
				// 非阻塞方式发送变更事件
				select {
				case changeChan <- vo.ConfigParam{DataId: dataId, Group: group}:
					// 成功发送
				default:
					nacos.Logger.Warn("配置变更通道已满，丢弃事件")
				}
			}
			callback(watchViper)
		},
		}); err != nil {
		nacos.Logger.Error("监听配置文件失败", zap.Error(err))
	}
}

// handleConfigChange
// Title 			handleConfigChange
// Description 		处理配置变更
// Author      		alittlexincan@163.com 												2024/07/22 11:36
// Param    		cp 						vo.ConfigParam 								配置参数
// Param    		callback 				factory.ConfigWatchRemoteConfigLoadFunc 	回调函数
func (nacos *nacosConfigComponent) handleConfigChange(cp vo.ConfigParam, callback factory.ConfigWatchRemoteConfigLoadFunc) {
	// 添加防抖处理，避免频繁变更
	time.Sleep(100 * time.Millisecond)

	watchViper := viper.New()
	watchViper.SetConfigType(constants.DefaultConfigSuffix)

	// 获取最新配置
	configClient := nacos.setNacosConfigServer()
	content, err := configClient.GetConfig(vo.ConfigParam{DataId: cp.DataId, Group: cp.Group})
	if err != nil {
		nacos.Logger.Error("处理配置变更时获取配置失败", zap.Error(err))
		return
	}

	if err := watchViper.ReadConfig(strings.NewReader(content)); err != nil {
		nacos.Logger.Error("处理配置变更时解析配置失败", zap.Error(err))
		return
	}

	// 更新本地缓存
	cacheKey := cp.DataId + ":" + cp.Group
	nacos.cacheMutex.Lock()
	nacos.localCache[cacheKey] = watchViper
	nacos.lastUpdateTime[cacheKey] = time.Now().Unix()
	nacos.cacheMutex.Unlock()

	// 回调通知
	callback(watchViper)
}

// setNacosConfigClient
// Title 			setNacosConfigClient
// Description 		内置辅助函数: 设置Nacos客户端配置
// Author      		alittlexincan@163.com       			2024/07/22 11:36
// Update  			alittlexincan@163.com 					2024/07/22 11:36
// Return    		*constant.ClientConfig				    返回Nacos客户端配置
func (nacos *nacosConfigComponent) setNacosConfigClient() *constant.ClientConfig {
	// 获取系统日志统一存储路径
	logPath := nacos.App.Config.Log.Path
	logDir, cacheDir, namespace := "", "", ""
	if nacos.LogDir == "" {
		if logPath == "" {
			logDir = constants.DefaultLogsDir + "/nacos/log"
		} else {
			logDir = filepath.Clean(logPath + "/nacos/log")
		}
	} else {
		logDir = filepath.Clean(nacos.LogDir + "/nacos/log")
	}

	if nacos.CacheDir == "" {
		cacheDir = filepath.Clean(constants.DefaultLogsDir + "/nacos/cache")
	} else {
		cacheDir = filepath.Clean(nacos.CacheDir + "/nacos/cache")
	}

	if nacos.NamespaceId != "public" {
		namespace = nacos.NamespaceId
	}
	return constant.NewClientConfig(
		constant.WithTimeoutMs(5000),            // 请求Nacos服务器超时时间，默认10000ms
		constant.WithNamespaceId(namespace),     // 命名空间ID，public命名空间留空
		constant.WithCacheDir(cacheDir),         // 缓存目录
		constant.WithLogDir(logDir),             // 日志目录
		constant.WithLogLevel("warn"),           // 日志级别: debug, info, warn, error
		constant.WithNotLoadCacheAtStart(true),  // 启动时不读取本地缓存
		constant.WithUpdateCacheWhenEmpty(true), // 从服务器获取空服务实例时更新缓存
		constant.WithUsername(nacos.Username),   // Nacos认证用户名
		constant.WithPassword(nacos.Password),   // Nacos认证密码
	)
}

// setNacosConfigServer
// Title 			setNacosConfigServer
// Description 		辅助函数: 设置Nacos服务器配置
// Author      		alittlexincan@163.com       			2024/07/22 11:36
// Update  			alittlexincan@163.com 					2024/07/22 11:36
// Return    		config_client.IConfigClient				返回Nacos服务器配置
func (nacos *nacosConfigComponent) setNacosConfigServer() config_client.IConfigClient {
	ipAddr := "127.0.0.1"
	if nacos.IP != "" {
		ipAddr = strings.Split(nacos.IP, "//")[1]
	}
	// 1. 创建Nacos服务器配置
	serverConfigs := []constant.ServerConfig{
		*constant.NewServerConfig(
			ipAddr,
			uint64(nacos.Port),
			constant.WithScheme(constant.DEFAULT_SERVER_SCHEME),
			constant.WithContextPath(constant.DEFAULT_CONTEXT_PATH),
		),
	}
	// 2. 创建Nacos配置客户端
	configClient, err := clients.NewConfigClient(vo.NacosClientParam{ClientConfig: nacos.setNacosConfigClient(), ServerConfigs: serverConfigs})
	if err != nil {
		nacos.Logger.Error("创建配置客户端失败", zap.Error(err))
	}
	return configClient
}

// init
// Title 			init
// Description 		初始化时自动实例化自身实例, 并在main包中导入当前包路径
// Author      		alittlexincan@163.com       			2024/07/17 11:36
// Update    		alittlexincan@163.com       			2024/07/17 11:36
func init() {
	factory.ConfigCenterFactory(constants.ProviderConfigNacos, &nacosConfigComponent{})
}
